home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-28 | 15.0 KB | 664 lines | [TEXT/MPS ] |
- /*
- File: FileOfFiles.cp
-
- Copyright: © 1991-1994 by Apple Computer, Inc.
- All rights reserved.
-
- Part of the AOCE Sample SMSAM Package. Consult the license
- which came with this software for your specific legal rights.
-
- */
-
-
-
- #ifndef __FILEOFFILES__
- #include "FileOfFiles.h"
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __FILES__
- #include <Files.h>
- #endif
-
- #ifndef __DEBUGASSERT__
- #include "DebugAssert.h"
- #endif
-
- #ifndef __DEBUGGINGGEAR__
- #include "DebuggingGear.h"
- #endif
-
- #ifndef __VIRTUALRAMORDISKFILE__
- #include "VirtualRamOrDiskFile.h"
- #endif
-
- #ifndef __STRING__
- #include "String.h"
- #endif
-
- /***********************************|****************************************/
-
- #pragma segment FileOfFiles
-
- /***********************************|****************************************/
-
- extern ostream& DumpHex (ostream& s, const void *p, unsigned long size);
-
- /***********************************|****************************************/
-
- inline long min ( long a, long b )
- {
- return ( a < b) ? a : b;
- }
-
- /***********************************|****************************************/
-
- ostream& TFileOfFiles::operator >> ( ostream& s ) const
- {
- s << "TFileOfFiles @ " << (void*) this;
- return TVirtualFile::operator >> ( s );
- }
-
- /***********************************|****************************************/
-
- class TCacheCache
- {
- public: TCacheCache ( const TFileOfFiles* );
- TCacheCache ( TVirtualFile*, long offset, unsigned long index );
- TCacheCache ();
- virtual ~TCacheCache ();
-
- void Save ( const TFileOfFiles* );
- void Restore ( TFileOfFiles* ) const;
-
- private: TVirtualFile* fCacheFile;
- long fCacheOffset;
- unsigned long fCacheIndex;
- };
-
- /***********************************|****************************************/
-
- TCacheCache::TCacheCache ( const TFileOfFiles* files ):
- fCacheFile ( files->fCacheFile ),
- fCacheOffset ( files->fCacheOffset ),
- fCacheIndex ( files->fCacheIndex )
- {
- }
-
- /***********************************|****************************************/
-
- TCacheCache::TCacheCache ( TVirtualFile* file, long offset, unsigned long index ):
- fCacheFile ( file ),
- fCacheOffset ( offset ),
- fCacheIndex ( index )
- {
- }
-
- /***********************************|****************************************/
-
- TCacheCache::~TCacheCache ()
- {
- }
-
- /***********************************|****************************************/
-
- void
- TCacheCache::Save ( const TFileOfFiles* files )
- {
- fCacheFile = files->fCacheFile;
- fCacheOffset = files->fCacheOffset;
- fCacheIndex = files->fCacheIndex;
- }
-
- /***********************************|****************************************/
-
- void
- TCacheCache::Restore ( TFileOfFiles* files ) const
- {
- files->fCacheFile = fCacheFile;
- files->fCacheOffset = fCacheOffset;
- files->fCacheIndex = fCacheIndex;
- }
-
- /***********************************|****************************************/
-
- static unsigned long gTestFileCount = 0;
- TVirtualFile* CreateTestFile ()
- {
- TVirtualFile* file = new TVirtualRamOrDiskFile;
-
- FAILNULL ( file );
- FAILOSErr ( file->SetEnd ( 0 ) );
- FAILOSErr ( file->SetPosition ( fsFromStart, 0 ) );
-
- unsigned long stop = ++gTestFileCount;
-
- for ( unsigned long i = 1; i <= stop; i++ )
- {
- FAILOSErr ( file->Write ( (const char) ( gTestFileCount + '@' ) ) );
- FAILOSErr ( file->Write ( (const char) ( i + (char) '0' ) ) );
- }
-
- FAILOSErr ( file->Write ( '|' ) );
-
- return file;
- }
-
- /***********************************|****************************************/
-
- TVirtualFile* CreateTestFileOfFiles ()
- {
- TFileOfFiles* fileOfFiles = new TFileOfFiles;
- fileOfFiles->AppendFile ( CreateTestFile () );
- fileOfFiles->AppendFile ( CreateTestFile () );
- fileOfFiles->AppendFile ( CreateTestFile () );
- return fileOfFiles;
- }
-
- /***********************************|****************************************/
-
- #if debug
-
- void VirtualFileTest ( TVirtualFile* file )
- {
- FAILNULL ( file );
-
- chris << "TVirtualFile:" << *file << endl;
-
- FAILOSErr ( file->SetPosition ( fsFromStart, 0 ) );
- chris << "after SetPosition(fsFromStart,0):" << *file << endl;
-
- FAILOSErr ( file->SetPosition ( fsFromLEOF, 0 ) );
- chris << "after SetPosition(fsFromLEOF,0):" << *file << endl;
-
- FAILOSErr ( file->SetEnd ( 10 ) );
- chris << "after SetEnd(10):" << *file << endl;
-
- FAILOSErr ( file->SetEnd ( 20 ) );
- chris << "after SetEnd(20):" << *file << endl;
-
- FAILOSErr ( file->SetEnd ( 0 ) );
- chris << "after SetEnd(0):" << *file << endl;
-
- const char* string = "this is a test string";
- FAILOSErr ( file->Write ( string ) );
- chris << "after Write(string):" << *file << endl;
- }
-
- /***********************************|****************************************/
-
- void FileOfFilesTests ()
- {
- TRY
- {
- TFileOfFiles* file = new TFileOfFiles;
-
- file->AppendFile ( CreateTestFileOfFiles () );
- file->AppendFile ( CreateTestFileOfFiles () );
- file->AppendFile ( CreateTestFileOfFiles () );
-
- VirtualFileTest ( file );
-
- for ( unsigned long index = 1; index <= file->NumFiles (); index++ )
- VirtualFileTest ( file->GetIndexFile ( index ) );
-
- VirtualFileTest ( file );
- }
- EXCEPTION
- {
- chris << "\n### WE CAUGHT AN EXCEPTION!!!!" << endl;
- }
- ENDEXCEPTION
- }
-
- #endif
-
- /***********************************|****************************************/
-
- TFileOfFiles::TFileOfFiles():
- TVirtualFile (),
- fFileList ( new TVirtualFileList ),
- fPosition ( 0 )
- {
- InvalidateCache ();
- }
-
- //--------------------------------------------------------------------------------
-
- TFileOfFiles::~TFileOfFiles()
- {
- unsigned long count = NumFiles ();
-
- while ( count > 0 )
- RemoveIndexFile ( count-- );
-
- delete fFileList;
- }
-
- //--------------------------------------------------------------------------------
-
- TVirtualFile* TFileOfFiles::RemoveIndexFile(unsigned long index)
- {
- InvalidateCache ();
-
- TVirtualFile* file = fFileList->Remove(index);
-
- if ( file )
- file->UnregisterReference();
-
- return file;
- }
-
- //--------------------------------------------------------------------------------
-
- OSErr TFileOfFiles::AppendFile(TVirtualFile* file)
- {
- return InsertFile ( file, NumFiles () + 1 );
- }
-
- //--------------------------------------------------------------------------------
-
- OSErr TFileOfFiles::InsertFile(TVirtualFile* file,unsigned long index)
- {
- FAILNULL ( file );
- TVirtualFile* cacheFile = fCacheFile;
- long cacheOffset = fCacheOffset;
- unsigned long cacheIndex = fCacheIndex;
-
- steveF ( 18, "TFileOfFile:InsertFile(), index=" << index );
-
- file->RegisterReference();
-
- if ( index >= 1 && index <= NumFiles () )
- {
- TVirtualFile* prevFile = fFileList->Get ( index );
-
- if ( prevFile )
- prevFile->UnregisterReference();
- }
-
- InvalidateCache ();
- fFileList->Insert ( index, file );
-
- return noErr;
- }
-
- //--------------------------------------------------------------------------------
-
- OSErr TFileOfFiles::GetSubFile ( unsigned long position, TVirtualFile*& subFile, long& offsetInSubfile, unsigned long& subFileIndex, Boolean makeFiles )
- {
- unsigned long offsetSoFar = 0; long chunkLength;
- const unsigned long numFiles = NumFiles ();
- OSErr error = noErr; subFileIndex = 0;
-
- // lock ourselves down because this routine might move memory yet it is
- // passed a reference to one of our members which might become invalid
- // if this object moves.
-
- ( (TFileOfFiles*) this )->Lock ();
-
- do
- {
- subFile = ++subFileIndex <= numFiles ? GetIndexFile ( subFileIndex ) : nil;
-
- // if no subfile exists, then we have to make a subfile and add it to the list
- if ( !subFile && makeFiles )
- {
- subFile = new TVirtualRamOrDiskFile ();
- if ( subFile )
- {
- error = subFile->SetEnd ( position - offsetSoFar );
- if ( error )
- {
- // we failed in setting up the subfile
- delete subFile;
- subFile = nil;
- break;
- }
- else
- {
- // now let’s add the subfile; save the cache because it might get
- // invalidated across this call since a reference is being passed into our routine
-
- TCacheCache cache ( this );
- ( (TFileOfFiles*) this )->AppendFile ( subFile );
- (void) cache.Restore ( this );
- }
- }
- }
-
- if ( subFile )
- {
- error = subFile->GetEnd ( chunkLength );
- if ( error )
- break;
-
- offsetInSubfile = position - offsetSoFar;
- offsetSoFar += chunkLength;
- }
- else
- {
- error = eofErr;
- }
- }
- while ( subFile && !error && offsetSoFar < position );
-
- ( (TFileOfFiles*) this )->Unlock ();
-
- return error;
- }
-
- /***********************************|****************************************/
-
- OSErr
- TFileOfFiles::ValidateCache ( Boolean makeFile )
- {
- OSErr error = noErr;
-
- if ( true || !fCacheFile )
- {
- error = GetSubFile ( fPosition, fCacheFile, fCacheOffset, fCacheIndex, makeFile );
- if ( error )
- InvalidateCache ();
- else
- {
- error = fCacheFile->SetPosition ( fsFromStart, fCacheOffset );
- if ( error )
- InvalidateCache ();
- }
- }
-
- return error;
- }
-
- /***********************************|****************************************/
-
- void TFileOfFiles::InvalidateCache ()
- {
- fCacheFile = nil;
- fCacheOffset = 0;
- fCacheIndex = 0;
- }
-
- /***********************************|****************************************/
-
- OSErr
- TFileOfFiles::GetNextCacheFile ()
- {
- fCacheFile = ++fCacheIndex <= NumFiles () ? GetIndexFile ( fCacheIndex ) : nil;
- return fCacheFile ? fCacheFile->SetPosition ( fsFromStart, fCacheOffset = 0 ) : eofErr;
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::ReadData ( void* bufferStart, long& bytesToRead )
- {
- char* buffer = (char*) bufferStart;
- long chunkLength = 0, bytesRemaining = bytesToRead;
- OSErr error = ValidateCache ( false ); Boolean cacheUpdate;
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::ReadData(" << bytesToRead << "). fPos=" << fPosition << endl;
- }
- #endif
-
- while ( fCacheFile && !error && bytesRemaining > 0 )
- {
- long fileLength;
- error = fCacheFile->GetEnd ( fileLength );
- if ( error )
- break;
-
- chunkLength = fileLength - fCacheOffset;
-
- if ( chunkLength >= bytesRemaining )
- {
- chunkLength = bytesRemaining;
- cacheUpdate = false;
- }
- else
- cacheUpdate = true;
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::Reading " << chunkLength << " bytes from subfile " << fCacheIndex <<
- " (of " << NumFiles() << " size=" << fileLength << ")" << endl;
- }
- #endif
-
- error = fCacheFile->ReadData ( buffer, chunkLength );
- if ( error )
- {
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::Read " << chunkLength << " bytes done. err=" << error << " remaining=" <<
- bytesRemaining << endl;
- }
- #endif
-
- break;
- }
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::Read " << chunkLength << " bytes done. err=" << error << " remaining=" <<
- bytesRemaining << endl;
- DumpHex(keith, buffer, min ( chunkLength, 48 ) );
- }
- #endif
-
- bytesRemaining -= chunkLength;
- buffer += chunkLength;
- fPosition += chunkLength;
-
- if ( bytesRemaining > 0 || cacheUpdate )
- error = GetNextCacheFile ();
- }
-
- bytesToRead -= bytesRemaining;
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::ReadData(" << bytesToRead << ") completed, err=" << error <<
- " fPos=" << fPosition << endl;
- }
- #endif
-
- return error;
- }
-
- /***********************************|****************************************/
-
- OSErr
- TFileOfFiles::Consolidate ()
- {
- NOT_IMPLEMENTED ();
- return noErr;
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::WriteData ( const void* bufferStart, long& bytesToWrite )
- {
- char* buffer = (char*) bufferStart;
- long chunkLength = 0, bytesRemaining = bytesToWrite;
- OSErr error = ValidateCache ( true ); unsigned long numFiles = NumFiles ();
-
- while ( bytesRemaining > 0 && fCacheFile && !error )
- {
- long fileLength = 0;
- if ( fCacheIndex >= numFiles )
- {
- chunkLength = bytesRemaining;
- }
- else
- {
- error = fCacheFile->GetEnd ( fileLength );
- if ( error )
- break;
-
- chunkLength = fileLength - fCacheOffset;
-
- if ( chunkLength > bytesRemaining )
- chunkLength = bytesRemaining;
- }
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::WriteData(" << chunkLength << ") bytes to subfile " << fCacheIndex <<
- " (of " << NumFiles() << " size=" << fileLength << ")" << endl;
- DumpHex(keith, buffer, min ( chunkLength, 48 ) );
- }
- #endif
-
- error = fCacheFile->WriteData ( buffer, chunkLength );
- if ( error )
- {
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::WriteData(), err=" << error << endl;
- }
- #endif
- break;
- }
-
- #if debug
- if (steveFlag.Flag(18)) {
- keith << "TFileOfFiles::WriteData(" << chunkLength << ") bytes done. Remaining=" <<
- bytesRemaining << endl;
- }
- #endif
-
- bytesRemaining -= chunkLength;
- buffer += chunkLength;
- fPosition += chunkLength;
-
- if ( bytesRemaining > 0 )
- error = GetNextCacheFile ();
- }
-
- bytesToWrite -= bytesRemaining;
-
- return error;
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::GetEnd ( long& length ) const
- {
- OSErr error = noErr;
- long totalLength = 0, subLength;
- unsigned long count = NumFiles ();
-
- while ( count > 0 )
- {
- const TVirtualFile* file = GetIndexFile ( count-- );
-
- if ( file )
- {
- error = file->GetEnd ( subLength );
- if ( error )
- break;
- else
- totalLength += subLength;
- }
- else
- {
- error = -1;
- break;
- }
- }
-
- length = totalLength;
-
- return error;
- }
-
- /***********************************|****************************************/
-
- unsigned long
- TFileOfFiles::GetEnd () const
- {
- long end = 0;
- FAILOSErr ( GetEnd ( end ) );
- return end;
- }
-
- /***********************************|****************************************/
-
- OSErr MoveEnd ( TVirtualFile& file, long delta )
- {
- long end = 0;
- OSErr error = file.GetEnd ( end );
- if ( !error ) error = file.SetEnd ( end + delta );
- return error;
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::SetEnd ( long requestedLength )
- {
- InvalidateCache ();
-
- OSErr error = noErr;
- TVirtualFile* subFile = nil;
- unsigned long count = NumFiles ();
- long actualLength = GetEnd ();
-
- if ( requestedLength < actualLength )
- {
- while ( count > 1 ) RemoveIndexFile ( count-- );
- subFile = GetIndexFile ( 1 ); FAILNULL ( subFile );
- error = subFile->SetEnd ( requestedLength );
- }
- else if ( requestedLength > actualLength )
- {
- if ( count == 0 ) InsertFile ( subFile = new TVirtualRamOrDiskFile, count++ );
- subFile = GetIndexFile ( count ); FAILNULL ( subFile );
- error = MoveEnd ( *subFile, requestedLength - actualLength );
- }
-
- if ( fPosition > requestedLength )
- fPosition = requestedLength;
-
- return error;
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::SetPosition ( short mode, long offset )
- {
- InvalidateCache ();
-
- long end = GetEnd ();
-
- if ( mode == fsFromLEOF )
- offset += end;
- else if ( mode == fsFromMark )
- offset += fPosition;
-
- if ( offset > end )
- {
- return eofErr;
- }
- else
- {
- fPosition = offset;
- return noErr;
- }
- }
-
- /***********************************|****************************************/
-
- OSErr TFileOfFiles::GetPosition ( long& position ) const
- {
- position = fPosition;
- return noErr;
- }
-
- /***********************************|****************************************/
-